package org.akomantoso.core.io.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.akomantoso.core.data.AkomaNtoso;
import org.akomantoso.core.data.AnyOtherTypeElement;
import org.akomantoso.core.io.InputFactory;
import org.akomantoso.core.io.util.Instantiator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author <a href="mailto:jacques.militello@gmail.com">Jacques Militello</a>
 */
public final class InputFactoryImpl extends InputFactory {

	private static final Logger LOGGER = LoggerFactory.getLogger(InputFactory.class);

	enum Version {
		V_1_0("http://www.akomantoso.org/1.0"), V_2_0("http://www.akomantoso.org/2.0");
		private final String _namespace;

		private Version(String namespace) {
			_namespace = namespace;
		}

		public String getNamespace() {
			return _namespace;
		}
	}

	/**
	 * @see org.akomantoso.core.io.InputFactory#read(java.io.InputStream, java.lang.String)
	 */
	@Override
	public AkomaNtoso read(InputStream stream, String encoding) throws IOException {

		final XMLStreamReader streamReader;

		try {
			streamReader = StaxXmlInput.XML_INPUT_FACTORY.createXMLStreamReader(stream, encoding);
		} catch (XMLStreamException cause) {
			throw new RuntimeException(cause);
		}

		while (!streamReader.isStartElement()) {
			try {
				streamReader.nextTag();
			} catch (XMLStreamException cause) {
				throw new RuntimeException(cause);
			}
		}

		for (int i = 0; i < streamReader.getNamespaceCount(); i++) {

			if (LOGGER.isTraceEnabled()) {
				LOGGER.trace("Check namespace [{}]", streamReader.getNamespaceURI(i));
			}

			if (Version.V_1_0.getNamespace().equals(streamReader.getNamespaceURI(i))) {
				return readVersion_1_0(streamReader);
			}

			if (Version.V_2_0.getNamespace().equals(streamReader.getNamespaceURI(i))) {
				return readVersion_2_0(streamReader);
			}

		}

		throw new RuntimeException("Version of Akoma Ntoso not supported ?!?");
	}

	private AkomaNtoso readVersion_2_0(XMLStreamReader reader) throws IOException {

		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Read Akoma Ntoso version 2.0");
		}

		final AkomaNtoso ntoso = new AkomaNtoso();
		ntoso.readExternal(new StaxXmlInput(this,reader));
		return ntoso;
	}

	private AkomaNtoso readVersion_1_0(XMLStreamReader reader) throws IOException {

		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Read Akoma Ntoso version 1.0");
		}

		final AkomaNtoso ntoso = new AkomaNtoso();
		//ntoso.readExternal(new StaxXmlInput(this,reader, true, BACKWARD_MAP_1));
		return ntoso;
	}

	public static final Map<String, Map<String, Instantiator<AnyOtherTypeElement>>> ADD = new HashMap<String, Map<String, Instantiator<AnyOtherTypeElement>>>();

	/**
	 * @see org.akomantoso.core.io.InputFactory#addTag(java.lang.String, java.lang.String, org.akomantoso.core.io.util.Instantiator)
	 */
	@Override
	public void addTag(String namespaceURI, String tagName, Instantiator<AnyOtherTypeElement> instantiator) {

		Map<String, Instantiator<AnyOtherTypeElement>> map = ADD.get(namespaceURI);
		
		if (map == null) {
			LOGGER.debug("Map null -> create new map for namespace [{}]", namespaceURI);
			map = new HashMap<String, Instantiator<AnyOtherTypeElement>>();
			ADD.put(namespaceURI, map);
		}

		map.put(tagName, instantiator);

	}

	
	/**
	 * @see org.akomantoso.core.io.InputFactory#getMap(java.lang.String)
	 */
	@Override
	public Map<String, Instantiator<AnyOtherTypeElement>> getMap(String namespaceURI) {
		return ADD.get(namespaceURI);
	}
	
}